#include "vpss_chn_imp.h"
#include "guard.h"

#include "mpi_vpss.h"

using namespace Json;
using namespace detu_infra;

namespace detu_media{

constexpr const VPSS_CHN_ATTR_S VpssChnImp::defaultChnAttr;

VpssChnImp::VpssChnImp(const VPSS_GRP grpId)
    : VpssChn(), fChnId(-1), fGrpId(grpId), fInited(false), fRef(0), fMutex(MUTEX_RECURSIVE)
{
	memset(&fChnAttr, 0, sizeof(VPSS_CHN_ATTR_S));
}

VpssChnImp::~VpssChnImp()
{
	if (isInited())
		deInit();
}

S_Result VpssChnImp::init(const Json::Value& config)
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		fChnId = (config.isMember("chnId") && config["chnId"].isIntegral()) ? config["chnId"].asInt() : -1;
		fChnAttr = defaultChnAttr;
		if (config.isMember("chnAttr"))
		{
			const Value& chnAttr = config["chnAttr"];
			
			if (chnAttr.isMember("width") && chnAttr["width"].isIntegral())
				fChnAttr.u32Width = chnAttr["width"].asUInt();

			if (chnAttr.isMember("height") && chnAttr["height"].isIntegral())
				fChnAttr.u32Height = chnAttr["height"].asUInt();

			if (chnAttr.isMember("videoFormat") && chnAttr["videoFormat"].isString())
			{
				const std::string& videoFormat = chnAttr["videoFormat"].asString();
				if (0 == videoFormat.compare("tile_16x8"))
					fChnAttr.enVideoFormat = VIDEO_FORMAT_TILE_16x8;
				else if (0 == videoFormat.compare("linear"))
					fChnAttr.enVideoFormat = VIDEO_FORMAT_LINEAR;
			}

			if (chnAttr.isMember("compressMode") && chnAttr["compressMode"].isString())
			{
				const std::string& compressMode = chnAttr["compressMode"].asString();
				if (0 == compressMode.compare("tile"))
					fChnAttr.enCompressMode = COMPRESS_MODE_TILE;
				else if (0 == compressMode.compare("seg"))
					fChnAttr.enCompressMode = COMPRESS_MODE_NONE;//COMPRESS_MODE_SEG;
				else if (0 == compressMode.compare("none"))
					fChnAttr.enCompressMode = COMPRESS_MODE_NONE;
			}

			if (chnAttr.isMember("frameRate"))
			{
				const Value& frameRate = chnAttr["frameRate"];
				
				if (frameRate.isMember("srcFrameRate") && frameRate["srcFrameRate"].isIntegral())
					fChnAttr.stFrameRate.s32SrcFrameRate = frameRate["srcFrameRate"].asInt();

				if (frameRate.isMember("dstFrameRate") && frameRate["dstFrameRate"].isIntegral())
					fChnAttr.stFrameRate.s32DstFrameRate = frameRate["dstFrameRate"].asInt();
			}
		}

		ret = S_OK;
		fInited = true;
	}
	while(0);

	return ret;
}

S_Result VpssChnImp::deInit()
{
	Guard guard(fMutex);
	if (isStarted())
	{
		fRef = 1;
		stop();
	}
	fGrpId = -1;
	fChnId = -1;
	memset(&fChnAttr, 0, sizeof(VPSS_CHN_ATTR_S));
	fInited = false;
	
	return S_OK;
}


S_Result VpssChnImp::start()
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (fRef < 0)
		{
			printf("start failed, fRef: %d < 0! grpId: %d, chnId: %d\n", fRef, fGrpId, fChnId);
			break;
		}
		
		if (fRef > 0)
		{
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("grpId: %d, chnId: %d not inited!\n", fGrpId, fChnId);
			break;
		}

		HI_S32 s32Ret = HI_MPI_VPSS_SetChnAttr(fGrpId, fChnId, &fChnAttr);

		if (s32Ret != HI_SUCCESS)
		{
			printf("HI_MPI_VPSS_SetChnAttr failed with %#x! grpId: %d, chnId: %d\n", s32Ret, fGrpId, fChnId);
			break;
		}
		
		s32Ret = HI_MPI_VPSS_EnableChn(fGrpId, fChnId);

		if (s32Ret != HI_SUCCESS)
		{
			printf("HI_MPI_VPSS_EnableChn failed with %#x! grpId: %d, chnId: %d\n", s32Ret, fGrpId, fChnId);
			break;
		}
		
		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef++;
	
	return ret;
}


S_Result VpssChnImp::stop()
{
	Guard guard(fMutex);
	S_Result ret = S_ERROR;
	do
	{
		if (fRef < 1)
		{
			printf("stop failed, fRef: %d < 1! grpId: %d, chnId: %d\n", fRef, fGrpId, fChnId);
			break;
		}
		
		if (fRef > 1)
		{
			ret = S_OK;
			break;
		}

		if (!isInited())
		{
			printf("grpId: %d, chnId: %d not inited!\n", fGrpId, fChnId);
			break;
		}		
		
		HI_S32 s32Ret = HI_MPI_VPSS_DisableChn(fGrpId, fChnId);

		if (s32Ret != HI_SUCCESS)
		{
			printf("HI_MPI_VPSS_DisableChn failed with %#x! grpId: %d, chnId: %d\n", s32Ret, fGrpId, fChnId);
			break;
		}
		
		ret = S_OK;
	}
	while(0);

	if (S_OK == ret)
		fRef--;
	
	return ret;
}

bool VpssChnImp::isInited()
{
    return fInited;
}

bool VpssChnImp::isStarted()
{
    return (fRef > 0);
}

S_Result VpssChnImp::getId(int &id)
{
    id = fChnId;

    return S_OK;
}

S_Result VpssChnImp::getVpssChnFrame(DT_VIDEO_FRAME_INFO_S* VideoFrameInfo, const Int32_t milliSec)
{
    Guard guard(fMutex);
	S_Result ret = S_ERROR;

    do
    {
        HI_S32 s32Ret = HI_MPI_VPSS_GetChnFrame(fGrpId, fChnId, (VIDEO_FRAME_INFO_S*)VideoFrameInfo, milliSec);
        printf("HI_MPI_VPSS_GetChnFrame is grpId: %d, pipeId: %d\n", fGrpId, fChnId);
        if(HI_SUCCESS != s32Ret)
        {
            printf("HI_MPI_VPSS_GetChnFrame failed with %#x! grpId: %d, fChnId: %d\n", s32Ret,fGrpId, fChnId);
            break;
        }
        ret = S_OK;
    }
    while(0);

    return ret;
}

S_Result VpssChnImp::releaseVpssChnFrame(DT_VIDEO_FRAME_INFO_S* VideoFrameInfo)
{
    Guard guard(fMutex);
	S_Result ret = S_ERROR;

    do
    {
        HI_S32 s32Ret = HI_MPI_VPSS_ReleaseChnFrame(fGrpId, fChnId, (VIDEO_FRAME_INFO_S*)VideoFrameInfo);
        printf("HI_MPI_VPSS_ReleaseChnFrame is grpId: %d, fChnId: %d\n", fGrpId, fChnId);
        if(HI_SUCCESS != s32Ret)
        {
            printf("HI_MPI_VPSS_ReleaseChnFrame failed! grpId: %d, fChnId: %d\n", fGrpId, fChnId);
            break;
        }
        ret = S_OK;
    }
    while(0);

    return ret;
}


}
